package ch.epfl.lara.pm.analyze;

import ch.epfl.lara.pm.ast._

object Util {
  import ch.epfl.lara.pm.parser._
  
  
  def findMatchExpressions(tree: Tree): List[Match] = tree match {
    
    case Program(_,objs,cls,expr) =>  
      findMatchExpressions(objs) :::
      findMatchExpressions(cls) :::
      findMatchExpressions(expr)
    
    case ObjectDef(_,extractor) => findMatchExpressions(extractor)
    
    case ExtractorDef(_,_,body) => findMatchExpressions(body)
    
    case ClassDef(_,_,_,_,methods) => findMatchExpressions(methods)
    
    case MethodDef(_,_,_,body) => findMatchExpressions(body)
    
    case CaseDef(_,_,guard,body) => Nil 
      /*findMatchExpressions(guard) ::: 
      findMatchExpressions(body)*/
      
    case Call(obj,_,args) =>
      findMatchExpressions(obj) :::
      findMatchExpressions(args)
      
    case Select(obj,_) =>
      findMatchExpressions(obj)
      
    case If(cond,then,elze) =>
      findMatchExpressions(cond) :::
      findMatchExpressions(then) :::
      findMatchExpressions(elze)
      
    case New(_,args) =>
      findMatchExpressions(args)
      
    case IsInstanceOf(e,tpe) =>
      findMatchExpressions(e)
      
    case Match(scrutinee,tpe,cases) => 
      Match(scrutinee,tpe,cases) :: findMatchExpressions(scrutinee) :::
      findMatchExpressions(cases) 
      
    case Plus(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case Minus(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case Prod(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case Div(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case Mod(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case Eq(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case Less(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
    
    case LessEq(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case EAnd(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case EOr(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case NotEq(left,right) => 
      findMatchExpressions(left) :::
      findMatchExpressions(right)
      
    case _ => Nil
  }
  
  def findMatchExpressions(trees: List[Tree]): List[Match] = 
    trees flatMap findMatchExpressions
    
  def findMatchExpressions(term: Option[Tree]): List[Match] = term match {
    case None => Nil
    case Some(tree) => findMatchExpressions(tree)
  }
  
  
  def alphabet(letter: Char): Stream[Char] =
    Stream.cons(letter, if(letter == 'Z' | letter == 'z') alphabet((letter-26).toChar) else alphabet((letter+1).toChar))
    
  def letters: Stream[String] = alphabet('a').zipWithIndex.map(pair => pair._1 + "" + pair._2 )
  
  val ALPHABET = alphabet('A')  
  
  private val SEP :String = "$"
  
  def freshSetName = { 
    counter += 1
    ALPHABET.head + SEP + counter
  }
  
  private var counter: Int = 0 
  
  def freshVarName(letter: String) = {
    counter += 1
    letter + SEP + counter
  }
}
